#include <pthread.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

static pthread_mutex_t chopsticks[5] = {
    PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER,
    PTHREAD_MUTEX_INITIALIZER
};

static float max_sleep_time = 1.0; //second
static int max_usecs = 0; //second

static void *eat(void *vp_chops) {
    pthread_mutex_t *chops_left = vp_chops;
    int id = chops_left - chopsticks;
    int seed = time(NULL);
    do {
        pthread_mutex_lock(chops_left);
        printf("Philosopher %c fetches chopstick %d\n", 'A'+id, id+1);
        pthread_mutex_lock(id==4 ?chopsticks: chops_left+1);
        printf("Philosopher %c fetches chopstick %d\n", 'A'+id, (id+1)%5+1);
        usleep(rand_r(&seed)/(double)RAND_MAX*max_usecs);
        pthread_mutex_unlock(chops_left);
        pthread_mutex_unlock(id==4 ?chopsticks: chops_left+1);
        printf("Philosopher %c release chopsticks %d %d\n", 
               'A'+id, 
               id+1, 
               (id+1)%5+1);
    } while(1);
}

int main(void) {
    int i;
    int c = 0;
    pthread_t tid;
    pthread_attr_t attr;

    puts("Input max sleep time(second: 1.0):");
    scanf("%f", &max_sleep_time);
    if(max_sleep_time <= 0) {
        max_sleep_time = 1.0;
    }
    max_usecs = max_sleep_time*1000000;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    
    for(i=0; i<5; i++) {
        pthread_create(&tid, NULL, &eat, chopsticks+i); 
    }
    while(c != EOF && (c=getchar())) {
        switch(c) {
        case 'q':
        case 'e':
        case 'Q':
        case 'E':
        case EOF:
            c=EOF;
            break;
        default:
            ;
        }
    }
    return 0;
    
}
